package nba2kmodtool.filedesc;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import nba2kmodtool.filedesc.util3d.DX3Dmath;
import nba2kmodtool.util.BufferUtil;
import nba2kmodtool.util.ByteFileReader;

class N2kIgModelExporter {
	private static final boolean IS_DEBUG = BaseIffFile.IS_DEBUG;

	protected BaseIffFile iff;
	protected File file;

	N2kIgModelExporter(BaseIffFile iff) {
		this.iff = iff;
		this.file = iff.file;
	}

	public void exportIgModel(File outfile, N2k3DModelPart[] models) throws IOException {
		ByteFileReader in = new ByteFileReader(file, "r");
		ByteFileReader out = new ByteFileReader(outfile, "rw");
		out.write("2KM".getBytes());
		out.write(0x00);
		int num = models.length;
		out.writeInt(Integer.reverseBytes(num));
		out.writeInt(Integer.reverseBytes(20));
		int partNum = 0;
		for (int i = 0; i < num; i++) {
			N2k3DModelPart part = models[i];
			if (part == null || part.childNum < 1) {
				continue;
			}
			List<FloatBuffer> vertexs = resolveIg3DModelVertexData(part, in);
			List<Integer> faces = iff.resolveIg3DModelFaceData(part, in);
			String partName = String.format("%d-0", i);
			out.write(partName.getBytes());
			for (int n = 0; n < 8 - partName.length(); n++) {
				out.write(0x00);
			}
			FloatBuffer vertBuf = vertexs.get(0);
			FloatBuffer uvnBuf = vertexs.get(1);
			int vertNum = vertBuf.array().length / 3;
			int faceNum = faces.size() / 3;
			out.writeInt(Integer.reverseBytes(vertNum));
			for (int n = 0; n < vertNum; n++) {
				out.writeIntBigEndin(Float.floatToIntBits(vertBuf.get()));
				out.writeIntBigEndin(Float.floatToIntBits(vertBuf.get()));
				out.writeIntBigEndin(Float.floatToIntBits(vertBuf.get()));
				out.writeIntBigEndin(Float.floatToIntBits(uvnBuf.get()));
				out.writeIntBigEndin(Float.floatToIntBits(uvnBuf.get()));
			}
			out.writeInt(Integer.reverseBytes(faceNum));
			int idx = 0;
			for (int n = 0; n < faceNum; n++) {
				out.writeShortBigEndin(faces.get(idx++));
				out.writeShortBigEndin(faces.get(idx++));
				out.writeShortBigEndin(faces.get(idx++));
			}
		}
		long len = out.getFilePointer();
		out.setLength(len);
		in.close();
		out.close();
	}

	List<FloatBuffer> resolveIg3DModelVertexData(N2k3DModelPart model, ByteFileReader in) throws IOException {
		int vertexNum = model.vertexNum;
		int perVertexSize = model.perVertexSize;
		int perUVNSize = model.perUVNSize;
		//get vertex position data buffer
		in.seek(model.vertexDataStart);
		ByteBuffer vBuf = ByteBuffer.allocate(vertexNum * perVertexSize);
		in.read(vBuf.array());
		vBuf.rewind();
		//resolve vertex data
		List<FloatBuffer> resultList = new ArrayList<FloatBuffer>();
		FloatBuffer tempVBuf = FloatBuffer.allocate(vertexNum * 3);
		FloatBuffer tempUVNBuf = FloatBuffer.allocate(vertexNum * 2);
		int dataChunkCount = model.dataChunkCount;
		//model type1
		if (dataChunkCount == 1) {
			//get vertex datas
			for (int i = 0; i < vertexNum; i++) {
				tempVBuf.put(BufferUtil.readFloat(vBuf));
				tempVBuf.put(BufferUtil.readFloat(vBuf));
				tempVBuf.put(BufferUtil.readFloat(vBuf));
				if ((perVertexSize - 12) == 0x28) {
					vBuf.position(vBuf.position() + 0x18);
					short tu = BufferUtil.readBytesAsShort(vBuf, 2);
					short tv = BufferUtil.readBytesAsShort(vBuf, 2);
					float[] uv = DX3Dmath.D3DXFloat16To32Array(new short[] { tu, tv });
					float u = uv[0];
					float v = 1.0F - uv[1];
					tempUVNBuf.put(u);
					tempUVNBuf.put(v);
					vBuf.position(vBuf.position() + 0x0C);
					continue;
				} else if ((perVertexSize - 12) == 0x24) {
					vBuf.position(vBuf.position() + 0x16);
					float mod = BufferUtil.readBytesAsInt(vBuf, 2);
					float u = BufferUtil.readBytesAsInt(vBuf, 2);
					float v = BufferUtil.readBytesAsInt(vBuf, 2);
					tempUVNBuf.put(u / 32767.0F);
					tempUVNBuf.put(1.0F - (v / 32767.0F));
					vBuf.position(vBuf.position() + 0x08);
					continue;
				} else {
					vBuf.position(vBuf.position() + (perVertexSize - 12));
				}
			}
		}
		//model type2
		else {
			//resolve vertex position
			if (perVertexSize == 8) {
				for (int i = 0; i < vertexNum; i++) {
					float x = BufferUtil.readBytesAsShort(vBuf, 2);
					float y = Math.abs(BufferUtil.readBytesAsShort(vBuf, 2));
					float z = BufferUtil.readBytesAsShort(vBuf, 2);
					float mod = BufferUtil.readBytesAsInt(vBuf, 2);
					x = x / 467.67F;
					y = y / 467.67F;
					z = z / 467.67F;
					tempVBuf.put(x);
					tempVBuf.put(y);
					tempVBuf.put(z);
				}
			} else {
				for (int i = 0; i < vertexNum; i++) {
					tempVBuf.put(BufferUtil.readFloat(vBuf));
					tempVBuf.put(BufferUtil.readFloat(vBuf));
					tempVBuf.put(BufferUtil.readFloat(vBuf));
					vBuf.position(vBuf.position() + (perVertexSize - 12));
				}
			}
			//get uvn position data buffer
			in.seek(model.uvnDataStart);
			ByteBuffer uvnBuf = ByteBuffer.allocate(vertexNum * perUVNSize);
			in.read(uvnBuf.array());
			uvnBuf.rewind();
			//resolve uv and normal data
			if (perUVNSize == 0x28) {
				for (int i = 0; i < vertexNum; i++) {
					uvnBuf.position(uvnBuf.position() + 0x18);
					tempUVNBuf.put(BufferUtil.readFloat(uvnBuf));
					tempUVNBuf.put(1.0F - BufferUtil.readFloat(uvnBuf));
					uvnBuf.position(uvnBuf.position() + 0x08);
				}
			} else if (perUVNSize == 0x24) {
				for (int i = 0; i < vertexNum; i++) {
					uvnBuf.position(uvnBuf.position() + 0x16);
					float mod = BufferUtil.readBytesAsInt(uvnBuf, 2);
					float u = BufferUtil.readBytesAsInt(uvnBuf, 2);
					float v = BufferUtil.readBytesAsInt(uvnBuf, 2);
					tempUVNBuf.put(u / 32767.0F);
					tempUVNBuf.put(1.0F - (v / 32767.0F));
					uvnBuf.position(uvnBuf.position() + 0x08);
				}
			} else if (perUVNSize == 0x18) {
				for (int i = 0; i < vertexNum; i++) {
					float u = BufferUtil.readBytesAsInt(uvnBuf, 2);
					float v = BufferUtil.readBytesAsInt(uvnBuf, 2);
					tempUVNBuf.put(u / 32767.0F);
					tempUVNBuf.put(1.0F - (v / 32767.0F));
					uvnBuf.position(uvnBuf.position() + 0x14);
				}
			} else {
				throw new IOException("UnSupport Nba2K 3D Model Type");
			}
		}
		tempVBuf.rewind();
		tempUVNBuf.rewind();
		resultList.add(tempVBuf);
		resultList.add(tempUVNBuf);
		return resultList;
	}

}
